package com.danicsoft.daide.serverclient;

import java.io.IOException;
import java.util.List;

import com.danicsoft.daide.binary.Connection;
import com.danicsoft.daide.command.AdminMessageCommand;
import com.danicsoft.daide.command.DefaultCommandTarget;
import com.danicsoft.daide.command.GoFlagCommand;
import com.danicsoft.daide.command.HelloCommand;
import com.danicsoft.daide.command.HistoryCommand;
import com.danicsoft.daide.command.HuhCommand;
import com.danicsoft.daide.command.IamCommand;
import com.danicsoft.daide.command.LoadCommand;
import com.danicsoft.daide.command.MapCommand;
import com.danicsoft.daide.command.MapDefinitionCommand;
import com.danicsoft.daide.command.MissingCommand;
import com.danicsoft.daide.command.NameCommand;
import com.danicsoft.daide.command.NotCommand;
import com.danicsoft.daide.command.NowCommand;
import com.danicsoft.daide.command.ObserverCommand;
import com.danicsoft.daide.command.OrderCommand;
import com.danicsoft.daide.command.OrderSpec;
import com.danicsoft.daide.command.ParenthesisCommand;
import com.danicsoft.daide.command.PissOffCommand;
import com.danicsoft.daide.command.SaveCommand;
import com.danicsoft.daide.command.SubmitCommand;
import com.danicsoft.daide.command.SupplyOwnershipCommand;
import com.danicsoft.daide.command.ThanksCommand;
import com.danicsoft.daide.command.TimeCommand;
import com.danicsoft.daide.command.Turn;
import com.danicsoft.daide.command.UnitPos;
import com.danicsoft.daide.token.StandardToken;
import com.danicsoft.daide.token.TokenMap;
import com.danicsoft.daide.token.TokenParser;
import com.danicsoft.daide.token.TokenMap.Phases;

/**
 * The <code>PlayerProxy</code> class stands between the server and the
 * network connection to the client. A server sends messages to a player proxy
 * and recieves requests or responses.
 * 
 * @author Daniel Yule (daniel.yule@gmail.com)
 * @version 1.0
 */
public final class PlayerProxy extends DefaultCommandTarget implements Player {

	/**
	 * Holds whether or not we are disconnected.
	 */
	private boolean disconnected = false;

	/**
	 * Holds if we are observing this game or not.
	 */
	private boolean isObserver = false;

	/**
	 * The server this proxy is attached to.
	 */
	private Server myServer;

	/**
	 * The name of this player
	 */
	private String name;

	/**
	 * The passcode of this player
	 */
	private int passcode;

	/**
	 * The power this player is playing as
	 */
	private StandardToken power;

	/**
	 * Whether or not we have sent SCO mesage this turn;
	 */
	private boolean sentSCO = false;

	/**
	 * The version of this player
	 */
	private String version;

	/**
	 * 
	 */
	private PLAYER_STATE state;

	/**
	 * Construct a new player proxy for communicating with the client
	 * 
	 * @param conn
	 *        The connection we have to the client
	 * @param parser
	 *        The parser we are going to use to parse messages recieved.
	 * @param myServer
	 *        The server we are associated with
	 * @throws IOException
	 */
	public PlayerProxy(Connection conn, TokenParser parser, DaideServer myServer) throws IOException {
		super(conn, parser);
		this.myServer = myServer;
		connect();

	}

	public void accept() {

	}

	public void acceptOrder(OrderSpec order, byte note) {
		sendCommand(new ThanksCommand(order, note));

	}

	/**
	 * Copys all the internal data from this <code>PlayerProxy</code> to
	 * <code>target</code>
	 * 
	 * @param target
	 *        The <code>PlayerProxy</code> to copy the data to.
	 */
	public void copyTo(PlayerProxy target) {
		// TODO Maintain a proper copy of the playerproxy
		target.myServer = myServer;
		target.name = name;
		target.passcode = passcode;
		target.version = version;
	}

	@Override
	public void disconnected() {
		disconnected = true;
		super.disconnected();
		myServer.left(this);
	}

	@Override
	public boolean equals(Object obj) {
		if (obj instanceof PlayerProxy) {
			PlayerProxy tProx = (PlayerProxy) obj;
			return tProx.passcode == passcode && tProx.power.equals(tProx.power);
		}
		return super.equals(obj);
	}

	public String getName() {
		return name;
	}

	public String getVersion() {
		return version;
	}

	/**
	 * Gets whether or not this player has been disconnected.
	 * 
	 * @return True if this player is disconnected, false otherwise.
	 */
	public boolean isDisconnected() {
		return disconnected;
	}

	/**
	 * Returns true if this is an observer
	 * 
	 * @return True if this is an observer
	 */
	public boolean isObserver() {
		return isObserver;
	}

	public void nextTurn(TurnInfo turn) {

		for (OrderCommand oc : turn.orders) {
			sendCommand(oc);
		}
		if (turn.turn.season.matches(TokenMap.PHASES, Phases.WIN) || (!sentSCO && turn.turn.season.matches(TokenMap.PHASES, Phases.SPR))) {
			sendCommand(turn.scOwnership);
			sentSCO = true;
		}
		else {
			sentSCO = false;
		}
		sendCommand(turn.armyPosition);

	}

	public void notifyOfMissingOrders(List<UnitPos> missingPositions) {
		sendCommand(new MissingCommand(missingPositions));

	}

	public void notifyOfMissingRemovals(int removalAmount) {
		sendCommand(new MissingCommand(removalAmount));

	}

	public void notifyOfMissingRetreats(List<UnitPos> missingRetreats) {
		sendCommand(new MissingCommand(missingRetreats));

	}

	public void reject() {
	// TODO Automatically generated

	}

	@Override
	public void sever() {
		disconnected = true;
		super.sever();
	}

	@Override
	protected void ReceivedHello(HelloCommand command) {
		if (command.isQuery()) {
			try {
				sendCommand(new HelloCommand(power, passcode, myServer.getVariantInfo()));
				return;
			}
			catch (IllegalServerStateException e) {

			}
		}
		super.ReceivedHello(command);

	}

	@Override
	protected void ReceivedIam(IamCommand command) {
		power = command.power;
		passcode = command.passcode;
		if (!myServer.rejoin(this)) {
			rejectCommand(command);
			power = null;
			passcode = 0;
		}
		else {
			acceptCommand(command);
		}

	}

	@Override
	protected void ReceivedMapDefintion(MapDefinitionCommand command) {
		if (command.isQuery()) {
			try {
				sendCommand(myServer.getMapInfo().defintion);
				return;
			}
			catch (IllegalServerStateException e) {

			}
		}
		super.ReceivedMapDefintion(command);

	}

	@Override
	protected void ReceivedName(NameCommand command) {
		name = command.name;
		version = command.version;
		if (myServer.join(this)) {
			acceptCommand(command);
			try {
				sendCommand(new MapCommand(myServer.getMapInfo().name));
				return;
			}
			catch (IllegalServerStateException e) {

			}
		}

		rejectCommand(command);
		name = null;
		version = null;

	}

	@Override
	protected void ReceivedNow(NowCommand command) {
		if (command.isQuery()) {
			try {
				sendCommand(myServer.getCurrentTurnInfo().armyPosition);
				return;
			}
			catch (IllegalServerStateException e) {

			}
		}

		super.ReceivedNow(command);

	}

	@Override
	protected void ReceivedObserver(ObserverCommand command) {
		if (myServer.observe(this)) {
			acceptCommand(command);
			try {
				sendCommand(new MapCommand(myServer.getMapInfo().name));
				isObserver = true;
				return;
			}
			catch (IllegalServerStateException e) {

			}

		}
		else {
			rejectCommand(command);
		}

	}

	@Override
	protected void ReceivedOff(PissOffCommand command) {
		myServer.left(this);

	}

	@Override
	protected void ReceivedOrder(OrderCommand command) {
		if (command.isQuery()) {
			TurnInfo thisInfo;
			try {
				thisInfo = myServer.getCurrentTurnInfo();
				for (OrderCommand order : thisInfo.orders) {
					sendCommand(order);
				}
				return;
			}
			catch (IllegalServerStateException e) {

			}

		}

		super.ReceivedOrder(command);

	}

	@Override
	protected void ReceivedParenthesis(ParenthesisCommand command) {
	// Do nothing. It can complain all we like
	// TODO add debug logging.

	}

	@Override
	protected void ReceivedSubmit(SubmitCommand command) {
		try {
			if (!command.isQuery()) {
				myServer.submitOrders(command.getOrders(), this);
				return;
			}
		}
		catch (IllegalServerStateException e) {

		}
		super.ReceivedSubmit(command);
	}

	@Override
	protected void ReceivedSupplyOwnership(SupplyOwnershipCommand command) {
		if (command.isQuery()) {
			try {
				sendCommand(myServer.getCurrentTurnInfo().scOwnership);

				return;
			}
			catch (IllegalServerStateException e) {

			}

		}

		super.ReceivedSupplyOwnership(command);

	}

	/**
	 * Start the game with the given information.
	 * 
	 * @param playerPower
	 *        The power this player will be playing.
	 * @param playerPasscode
	 *        The passcode this player will be associated with
	 * @param startingTurn
	 *        The turn information for the first turn.
	 * @see com.danicsoft.daide.serverclient.Player#startGame(StandardToken,
	 *      int, VariantInfo, TurnInfo)
	 */
	public void startGame(StandardToken playerPower, int playerPasscode, VariantInfo info, TurnInfo startingTurn) {
		this.power = playerPower;
		this.passcode = playerPasscode;

		sendCommand(new HelloCommand(power, passcode, info));

		startGame(startingTurn);

	}

	/**
	 * Inform the observer that we are starting the game.
	 * 
	 * @param startingTurn
	 *        The turn information for the first turn. Does not contain any
	 *        order information.
	 */
	public void startGame(TurnInfo startingTurn) {
		sendCommand(startingTurn.scOwnership);
		sendCommand(startingTurn.armyPosition);

	}

	@Override
	protected void AcceptedLoad(LoadCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void AcceptedMap(MapCommand command) {
		myServer.ready(this);

	}

	public PLAYER_STATE getState() {
		return state;
	}

	@Override
	protected void AcceptedGoFlag(GoFlagCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void AcceptedNot(NotCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void AcceptedSave(SaveCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void AcceptedTime(TimeCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void ReceivedAdminMessage(AdminMessageCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void ReceivedGoFlag(GoFlagCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void ReceivedHistory(HistoryCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void ReceivedNot(NotCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void ReceivedSave(SaveCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void ReceivedTime(TimeCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void RejectedAdminMessage(AdminMessageCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void RejectedGoFlag(GoFlagCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void RejectedHistory(HistoryCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void RejectedNot(NotCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void RejectedSave(SaveCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void RejectedTime(TimeCommand command) {
	// TODO Automatically generated

	}

	@Override
	protected void ReceivedHuh(HuhCommand command) {
	// TODO Automatically generated

	}

	public void adminMessage(String from, String message) {
		sendCommand(new AdminMessageCommand(from, message));

	}

	public void notifyUpcomingDeadline(int secondsLeft) {
		sendCommand(new TimeCommand(secondsLeft));

	}

	public void notifyMapInfo(MapInfo mInfo) {

	}



	public int getPasscode() {
		return passcode;
	}

	public StandardToken getPower() {
		return power;
	}

	public void endGame(List<StandardToken> winners, Turn turn) {
		//TODO Automatically generated
		
	}

}
